/***********************************************************
 *  File_Name  : XJBufferPool.h
 *  File_Path   :
 *  File_Encode : UTF8
 *  Description : 简单内存缓冲池
 *
 *  OS : Linux, UNIX, Windows
 *  LastVersion  : 20150918
 *
 *  Author      : LiXiujie(李秀杰)
 *  Date        : 2015-9-18
 *  Version     : 20150918
 *  Description :
 *
 *  Edit Author :
 *  Edit Date   :
 *  Version     :
 *  Description :
 *
 ***********************************************************/

#ifndef SRC_XJBUFFERPOOL_H_
#define SRC_XJBUFFERPOOL_H_

#include <map>

#include "XJEnv.h"
#include "XJRWLock.h"
#include "XJSingleton.h"
#include "XJPrivateHeap.h"
#include "XJMutex.h"

#ifdef __GXX_EXPERIMENTAL_CXX0X__
#if __cpp_lib_unordered_map >= 201003L  
#include <unordered_map>
#else
#include <tr1/unordered_map>
#endif
#endif

#ifndef _WIN32

#ifndef ASSERT
#include <assert.h>
#define ASSERT(p) assert(p)
#endif

#endif

namespace XJUtilClass{

template<class T> struct TSimpleList;

struct	TItemList;
class	XJItemPool;
struct	TBuffer;
class	XJBufferPool;

struct TItem
{
public:
	template<typename T>
	friend struct	TSimpleList;
	friend struct	TItemList;
	friend class	XJItemPool;
	friend struct	TBuffer;

public:
	inline int Cat		(const unsigned char* pData, int length);
	inline int Cat		(const TItem& other);
	inline int Fetch	(unsigned char* pData, int length);
	inline int Reduce	(int length);
	inline void	Reset	(int first = 0, int last = 0);

	unsigned char*		Ptr		()			{return begin;}
	const unsigned char*	Ptr		()	const	{return begin;}
	int			Size	()	const	{return (int)(end - begin);}
	int			Remain	()	const	{return capacity - (int)(end - head);}
	int			Capacity()	const	{return capacity;}
	bool		IsEmpty	()	const	{return Size()	 == 0;}
	bool		IsFull	()	const	{return Remain() == 0;}

public:
	operator		unsigned char*	()			{return Ptr();}
	operator const	unsigned char*	() const	{return Ptr();}

public:
	static TItem* Construct(XJPrivateHeap& heap,
							int		capacity	= DEFAULT_ITEM_CAPACITY,
							unsigned char*	pData		= NULL,
							int		length		= 0);

	static void Destruct(TItem* pItem);

private:
	TItem(XJPrivateHeap& hp, int cap = DEFAULT_ITEM_CAPACITY, unsigned char* pData = NULL, int length = 0)
	: heap(hp), capacity(cap), begin(head), end(head), next(NULL), last(NULL)
	{
		if(pData != NULL && length != 0)
			Cat(pData, length);
	}

	~TItem() {}

	DECLARE_NO_COPY_CLASS(TItem)

public:
	static const unsigned long DEFAULT_ITEM_CAPACITY;

private:
	XJPrivateHeap& heap;

private:
	TItem* next;
	TItem* last;

	int		capacity;
	unsigned char*	head;
	unsigned char*	begin;
	unsigned char*	end;
};

template<class T> struct TSimpleList
{
public:
	T* PushFront(T* pItem)
	{
		if(pFront != NULL)
		{
			pFront->last = pItem;
			pItem->next	 = pFront;
		}
		else
		{
			pItem->last = NULL;
			pItem->next = NULL;
			pBack		= pItem;
		}

		pFront = pItem;
		++size;

		return pItem;
	}

	T* PushBack(T* pItem)
	{
		if(pBack != NULL)
		{
			pBack->next	= pItem;
			pItem->last	= pBack;
		}
		else
		{
			pItem->last = NULL;
			pItem->next = NULL;
			pFront		= pItem;
		}

		pBack = pItem;
		++size;

		return pItem;
	}

	T* PopFront()
	{
		T* pItem = pFront;

		if(pFront != pBack)
		{
			pFront = pFront->next;
			pFront->last = NULL;
		}
		else if(pFront != NULL)
		{
			pFront	= NULL;
			pBack	= NULL;
		}

		if(pItem != NULL)
		{
			pItem->next = NULL;
			pItem->last = NULL;

			--size;
		}

		return pItem;
	}

	T* PopBack()
	{
		T* pItem = pBack;

		if(pFront != pBack)
		{
			pBack = pBack->last;
			pBack->next	= NULL;
		}
		else if(pBack != NULL)
		{
			pFront	= NULL;
			pBack	= NULL;
		}

		if(pItem != NULL)
		{
			pItem->next = NULL;
			pItem->last = NULL;

			--size;
		}

		return pItem;
	}

	TSimpleList<T>& Shift(TSimpleList<T>& other)
	{
		if(other.size > 0)
		{
			if(size > 0)
			{
				pBack->next = other.pFront;
				other.pFront->last = pBack;
			}
			else
			{
				pFront = other.pFront;
			}

			pBack	 = other.pBack;
			size	+= other.size;

			other.Reset();
		}

		return *this;
	}

	void Clear()
	{
		if(size > 0)
		{
			T* pItem;
			while((pItem = PopFront()) != NULL)
				T::Destruct(pItem);
		}
	}

	T*		Front	()	const	{return pFront;}
	T*		Back	()	const	{return pBack;}
	int		Size	()	const	{return size;}
	bool	IsEmpty	()	const	{return size == 0;}

public:
	TSimpleList()	{Reset();}
	~TSimpleList()	{Clear();}

	DECLARE_NO_COPY_CLASS(TSimpleList<T>)

private:
	void Reset()
	{
		pFront	= NULL;
		pBack	= NULL;
		size	= 0;
	}

private:
	int	size;
	T*	pFront;
	T*	pBack;
};

struct TItemList : public TSimpleList<TItem>
{
public:
	int Cat		(const unsigned char* pData, int length);
	int Cat		(const TItem* pItem);
	int Cat		(const TItemList& other);
	int Fetch	(unsigned char* pData, int length);
	int Reduce	(int length);
	void Release();

public:
	TItemList(XJItemPool& pool) : itPool(pool)
	{
	}

private:
	XJItemPool& itPool;
};

struct TItemListEx : public TItemList
{
public:
	TItem* PushFront(TItem* pItem)
	{
		length += pItem->Size();
		return TSimpleList<TItem>::PushFront(pItem);
	}

	TItem* PushBack(TItem* pItem)
	{
		length += pItem->Size();
		return TSimpleList<TItem>::PushBack(pItem);
	}

	TItem* PopFront()
	{
		TItem* pItem = TSimpleList<TItem>::PopFront();

		if(pItem != NULL)
			length -= pItem->Size();

		return pItem;
	}

	TItem* PopBack()
	{
		TItem* pItem = TSimpleList<TItem>::PopBack();

		if(pItem != NULL)
			length -= pItem->Size();

		return pItem;
	}

	TItemListEx& Shift(TItemListEx& other)
	{
		length += other.length;
		TSimpleList<TItem>::Shift(other);
		other.length = 0;

		return *this;
	}

	void Clear()
	{
		TSimpleList<TItem>::Clear();
		length = 0;
	}

	void Release()
	{
		TItemList::Release();
		length = 0;
	}

public:
	int Cat(const unsigned char* pData, int length)
	{
		int cat = TItemList::Cat(pData, length);
		this->length += cat;

		return cat;
	}

	int Cat(const TItem* pItem)
	{
		int cat = TItemList::Cat(pItem->Ptr(), pItem->Size());
		this->length += cat;

		return cat;
	}

	int Cat(const TItemList& other)
	{
		int cat = TItemList::Cat(other);
		this->length += cat;

		return cat;
	}

	int Fetch(unsigned char* pData, int length)
	{
		int fetch	= TItemList::Fetch(pData, length);
		this->length -= fetch;

		return fetch;
	}

	int Reduce(int length)
	{
		int reduce	= TItemList::Reduce(length);
		this->length -= reduce;

		return reduce;
	}

	int Length() const {return length;}

public:
	TItemListEx(XJItemPool& pool) : TItemList(pool), length(0)
	{
	}

	~TItemListEx()
	{
		ASSERT(length >= 0);
	}

	DECLARE_NO_COPY_CLASS(TItemListEx)

private:
	int length;
};

class XJItemPool
{
public:
	void PutFreeItem	(TItem* pItem);
	void PutFreeItem	(TItemList& lsItem);
	TItem* PickFreeItem	();

	inline void Clear();

private:
	void CompressFreeItem(int size);

public:
	void SetItemCapacity(unsigned long dwItemCapacity)	{m_dwItemCapacity	= dwItemCapacity;}
	void SetPoolSize	(unsigned long dwPoolSize)		{m_dwPoolSize		= dwPoolSize;}
	void SetPoolHold	(unsigned long dwPoolHold)		{m_dwPoolHold		= dwPoolHold;}
	unsigned long GetItemCapacity	()					{return m_dwItemCapacity;}
	unsigned long GetPoolSize		()					{return m_dwPoolSize;}
	unsigned long GetPoolHold		()					{return m_dwPoolHold;}

public:
	XJItemPool(	unsigned long dwPoolSize	 = DEFAULT_POOL_SIZE,
				unsigned long dwPoolHold	 = DEFAULT_POOL_HOLD,
				unsigned long dwItemCapacity = DEFAULT_ITEM_CAPACITY)
	: m_dwPoolSize(dwPoolSize)
	, m_dwPoolHold(dwPoolHold)
	, m_dwItemCapacity(dwItemCapacity)
	, m_lsFreeItem(*this)
	{
	}

	~XJItemPool()	{Clear();}

	DECLARE_NO_COPY_CLASS(XJItemPool)

public:
	static const unsigned long DEFAULT_ITEM_CAPACITY;
	static const unsigned long DEFAULT_POOL_SIZE;
	static const unsigned long DEFAULT_POOL_HOLD;

private:
	XJPrivateHeap	m_heap;

	unsigned long			m_dwItemCapacity;
	unsigned long			m_dwPoolSize;
	unsigned long			m_dwPoolHold;

	XJMutex			m_csFreeItem;
	TItemList		m_lsFreeItem;
};

struct TItemPtr
{
public:
	TItem* Reset(TItem* pItem = NULL)
	{
		if(m_pItem != NULL)
			itPool.PutFreeItem(m_pItem);

		m_pItem = pItem;

		return m_pItem;
	}

	TItem* Attach(TItem* pItem)
	{
		return Reset(pItem);
	}

	TItem* Detach()
	{
		TItem* pItem = m_pItem;
		m_pItem		 = NULL;

		return pItem;
	}

	bool IsValid			()				{return m_pItem != NULL;}
	TItem* operator ->		()				{return m_pItem;}
	TItem* operator =		(TItem* pItem)	{return Reset(pItem);}
	operator TItem*			()				{return m_pItem;}
	TItem* Ptr				()				{return m_pItem;}
	const TItem* Ptr		()	const		{return m_pItem;}
	operator const TItem*	()	const		{return m_pItem;}

public:
	TItemPtr(XJItemPool& pool, TItem* pItem = NULL)
	: itPool(pool), m_pItem(pItem)
	{

	}

	~TItemPtr()
	{
		Reset();
	}

	DECLARE_NO_COPY_CLASS(TItemPtr)

private:
	XJItemPool&	itPool;
	TItem*		m_pItem;
};

struct TBuffer
{
public:
	template<typename T> friend class TSimpleList;
	friend class XJBufferPool;

public:
	static TBuffer* Construct(XJBufferPool& pool_, unsigned long int dwID);
	static void Destruct(TBuffer* pBuffer);

public:
	int Cat		(const unsigned char* pData, int len);
	int Cat		(const TItem* pItem);
	int Cat		(const TItemList& other);
	int Fetch	(unsigned char* pData, int length);
	int Reduce	(int len);

public:
	XJMutex&	CriSec	()	{return cs;}
	TItemList&	ItemList()	{return items;}

	unsigned long ID		()	const	{return id;}
	int Length			()	const	{return length;}
	bool IsValid		()	const	{return id != 0;}

private:
	int IncreaseLength	(int len)	{return (length += len);}
	int DecreaseLength	(int len)	{return (length -= len);}

	inline void Reset	();

private:
	TBuffer(XJPrivateHeap& hp, XJItemPool& itPool, unsigned long dwID = 0)
	: heap(hp), items(itPool), id(dwID), length(0),freeTime(0),last(NULL),next(NULL)
	{
	}

	~TBuffer()	{}

	DECLARE_NO_COPY_CLASS(TBuffer)

private:
	XJPrivateHeap&	heap;

private:
	unsigned long		id;
	int				length;
	unsigned long			freeTime;

private:
	TBuffer*		next;
	TBuffer*		last;

	XJMutex			cs;
	TItemList		items;
};

typedef TSimpleList<TBuffer>				TBufferList;
#ifdef __GXX_EXPERIMENTAL_CXX0X__
#if __cpp_lib_unordered_map >= 201003L  
typedef std::unordered_map<unsigned long, TBuffer*>	TBufferPtrMap;
#else
typedef std::tr1::unordered_map<unsigned long, TBuffer*>	TBufferPtrMap;
#endif
#else
typedef std::map<unsigned long, TBuffer* >	TBufferPtrMap;
#endif
typedef TBufferPtrMap::iterator				TBufferPtrMapI;
typedef TBufferPtrMap::const_iterator		TBufferPtrMapCI;

class XJBufferPool
{
public:
	void		PutFreeBuffer	(unsigned long dwID);
	void		PutCacheBuffer	(unsigned long dwID);
	TBuffer*	PickFreeBuffer	(unsigned long dwID);
	TBuffer*	FindCacheBuffer	(unsigned long dwID);

	void		Clear			();

private:
	void PutFreeBuffer		(TBuffer* pBuffer);
	void CompressFreeBuffer	(int size);

public:
	void SetItemCapacity	(unsigned long dwItemCapacity)		{m_itPool.SetItemCapacity(dwItemCapacity);}
	void SetItemPoolSize	(unsigned long dwItemPoolSize)		{m_itPool.SetPoolSize(dwItemPoolSize);}
	void SetItemPoolHold	(unsigned long dwItemPoolHold)		{m_itPool.SetPoolHold(dwItemPoolHold);}

	void SetBufferLockTime	(unsigned long dwBufferLockTime)	{m_dwBufferLockTime	= dwBufferLockTime;}
	void SetBufferPoolSize	(unsigned long dwBufferPoolSize)	{m_dwBufferPoolSize	= dwBufferPoolSize;}
	void SetBufferPoolHold	(unsigned long dwBufferPoolHold)	{m_dwBufferPoolHold	= dwBufferPoolHold;}

	unsigned long GetItemCapacity	()							{return m_itPool.GetItemCapacity();}
	unsigned long GetItemPoolSize	()							{return m_itPool.GetPoolSize();}
	unsigned long GetItemPoolHold	()							{return m_itPool.GetPoolHold();}

	unsigned long GetBufferLockTime	()							{return m_dwBufferLockTime;}
	unsigned long GetBufferPoolSize	()							{return m_dwBufferPoolSize;}
	unsigned long GetBufferPoolHold	()							{return m_dwBufferPoolHold;}

	TBuffer* operator []	(unsigned long dwID)			{return FindCacheBuffer(dwID);}

public:
	XJBufferPool(unsigned long dwPoolSize	 = DEFAULT_BUFFER_POOL_SIZE,
				unsigned long dwPoolHold	 = DEFAULT_BUFFER_POOL_HOLD,
				unsigned long dwLockTime	 = DEFAULT_BUFFER_LOCK_TIME,
				unsigned long dwItemCapacity = DEFAULT_ITEM_CAPACITY)
	: m_dwBufferPoolSize(dwPoolSize)
	, m_dwBufferPoolHold(dwPoolHold)
	, m_dwBufferLockTime(dwLockTime)
	{
		m_itPool.SetItemCapacity(dwItemCapacity);
	}

	~XJBufferPool()	{Clear();}

	DECLARE_NO_COPY_CLASS(XJBufferPool)

public:
	XJPrivateHeap&	GetPrivateHeap()	{return m_heap;}
	XJItemPool&		GetItemPool()		{return m_itPool;}

public:
	static const unsigned long DEFAULT_ITEM_CAPACITY;
	static const unsigned long DEFAULT_ITEM_POOL_SIZE;
	static const unsigned long DEFAULT_ITEM_POOL_HOLD;
	static const unsigned long DEFAULT_BUFFER_LOCK_TIME;
	static const unsigned long DEFAULT_BUFFER_POOL_SIZE;
	static const unsigned long DEFAULT_BUFFER_POOL_HOLD;

private:
	unsigned long			m_dwBufferLockTime;
	unsigned long			m_dwBufferPoolSize;
	unsigned long			m_dwBufferPoolHold;

	XJPrivateHeap	m_heap;
	XJItemPool		m_itPool;

	XJRWLock			m_csBufferMap;

	TBufferPtrMap	m_mpBuffer;

	XJMutex			m_csFreeBuffer;
	TBufferList		m_lsFreeBuffer;
};

}//namespace XJUtilClass

#endif /* SRC_XJBUFFERPOOL_H_ */
